package cn.csc.module.product.service.stocklock;

import cn.csc.framework.common.exception.ServiceException;
import cn.csc.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.csc.framework.common.pojo.CommonResult;
import cn.csc.framework.common.pojo.PageResult;
import cn.csc.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.csc.module.order.api.order.OrderApi;
import cn.csc.module.order.api.order.dto.OrderStatusRespDTO;
import cn.csc.module.order.enums.OrderStatusEnum;
import cn.csc.module.product.api.stocklock.dto.SkuStockLockReqDTO;
import cn.csc.module.product.controller.admin.stocklock.vo.SkuStockLockCreateReqVO;
import cn.csc.module.product.controller.admin.stocklock.vo.SkuStockLockExportReqVO;
import cn.csc.module.product.controller.admin.stocklock.vo.SkuStockLockPageReqVO;
import cn.csc.module.product.controller.admin.stocklock.vo.SkuStockLockUpdateReqVO;
import cn.csc.module.product.convert.stocklock.SkuStockLockConvert;
import cn.csc.module.product.dal.dataobject.stock.SkuStockDO;
import cn.csc.module.product.dal.dataobject.stocklock.SkuStockLockDO;
import cn.csc.module.product.dal.mysql.extension.SpuExtensionMapper;
import cn.csc.module.product.dal.mysql.sku.SkuMapper;
import cn.csc.module.product.dal.mysql.spu.SpuMapper;
import cn.csc.module.product.dal.mysql.stock.SkuStockMapper;
import cn.csc.module.product.dal.mysql.stocklock.SkuStockLockMapper;
import cn.csc.module.product.mq.producer.stocklock.SkuStockLockProducer;
import cn.hutool.core.collection.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;

import static cn.csc.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.csc.module.product.enums.ErrorCodeConstants.*;

/**
 * 库存锁定信息 Service 实现类
 *
 * @author liuchuang
 */
@Slf4j
@Service
@Validated
public class SkuStockLockServiceImpl implements SkuStockLockService {

    @Resource
    private SkuStockLockMapper skuStockLockMapper;

    @Autowired
    private SkuStockMapper skuStockMapper;

    @Autowired
    private SpuExtensionMapper spuExtensionMapper;

    @Resource
    private SkuStockLockProducer skuStockLockProducer;

    @Resource
    private OrderApi orderApi;
    @Resource
    private SkuMapper skuMapper;
    @Resource
    private SpuMapper spuMapper;

    @Override
    public BigInteger createSkuStockLock(SkuStockLockCreateReqVO createReqVO) {
        // 插入
        SkuStockLockDO skuStockLock = SkuStockLockConvert.INSTANCE.convert(createReqVO);
        skuStockLockMapper.insert(skuStockLock);
        // 返回
        return skuStockLock.getId();
    }

    @Override
    public void updateSkuStockLock(SkuStockLockUpdateReqVO updateReqVO) {
        // 校验存在
        validateSkuStockLockExists(updateReqVO.getId());
        // 更新
        SkuStockLockDO updateObj = SkuStockLockConvert.INSTANCE.convert(updateReqVO);
        skuStockLockMapper.updateById(updateObj);
    }

    @Override
    public void deleteSkuStockLock(BigInteger id) {
        // 校验存在
        validateSkuStockLockExists(id);
        // 删除
        skuStockLockMapper.deleteById(id);
    }

    private void validateSkuStockLockExists(BigInteger id) {
        if (skuStockLockMapper.selectById(id) == null) {
            throw exception(SKU_STOCK_LOCK_NOT_EXISTS);
        }
    }

    @Override
    public SkuStockLockDO getSkuStockLock(BigInteger id) {
        return skuStockLockMapper.selectById(id);
    }

    @Override
    public List<SkuStockLockDO> getSkuStockLockList(Collection<BigInteger> ids) {
        return skuStockLockMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<SkuStockLockDO> getSkuStockLockPage(SkuStockLockPageReqVO pageReqVO) {
        return skuStockLockMapper.selectPage(pageReqVO);
    }

    @Override
    public List<SkuStockLockDO> getSkuStockLockList(SkuStockLockExportReqVO exportReqVO) {
        return skuStockLockMapper.selectList(exportReqVO);
    }

    /**
     * 锁定库存
     *
     * @param skuStockLocksParam 参数
     * @return 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void lock(List<SkuStockLockReqDTO> skuStockLocksParam) {
        List<SkuStockLockDO> skuStockLocks = new ArrayList<>();
        for (SkuStockLockReqDTO skuStockLockDTO : skuStockLocksParam) {
            SkuStockLockDO skuStockLock = new SkuStockLockDO();
            skuStockLock.setCount(skuStockLockDTO.getCount());
            skuStockLock.setOrderId(skuStockLockDTO.getOrderId());
            skuStockLock.setSkuId(skuStockLockDTO.getSkuId());
            skuStockLock.setSpuId(skuStockLockDTO.getSpuId());
            skuStockLock.setStatus(0);
            skuStockLocks.add(skuStockLock);
            // 减sku库存
            int skuStockUpdateIsSuccess = skuStockMapper.reduceStockByOrder(skuStockLockDTO.getSkuId(), skuStockLockDTO.getCount());
            if (skuStockUpdateIsSuccess < 1) {
                // 库存不足
                SKU_STOCK_LOCK_UNDER_STOCK.setMsg(String.format(SKU_STOCK_LOCK_UNDER_STOCK.getMsg(), skuStockLockDTO.getSkuId()));
                throw exception(SKU_STOCK_LOCK_UNDER_STOCK);
            }
            // 减商品库存
            int spuStockUpdateIsSuccess = spuExtensionMapper.reduceStockByOrder(skuStockLockDTO.getSpuId(), skuStockLockDTO.getCount());
            if (spuStockUpdateIsSuccess < 1) {
                // 库存不足
                SKU_STOCK_LOCK_UNDER_STOCK.setMsg(String.format(SKU_STOCK_LOCK_UNDER_STOCK.getMsg(), skuStockLockDTO.getSkuId()));
                throw exception(SKU_STOCK_LOCK_UNDER_STOCK);
            }
        }
        // 保存库存锁定信息
        skuStockLockMapper.insertBatch(skuStockLocks);

        List<BigInteger> orderIds = skuStockLocksParam.stream().map(SkuStockLockReqDTO::getOrderId).collect(Collectors.toList());
        // 半小时后解锁库存，发送延迟mq消息
        Boolean sendFlag = skuStockLockProducer.sendSkuStockLockMessage(orderIds);
        if (!sendFlag) {
            // 消息发送失败，回滚事务
            throw exception(SKU_STOCK_LOCK_MESSAGE_SEND_FAIL);
        }
        // 锁定库存成功
    }

    @Transactional
    @Override
    public void decreStock(List<SkuStockLockReqDTO> skuStockLocksParam) {
        skuStockLocksParam.forEach(s -> {
            skuStockMapper.updateStockNumberByOrder(s.getSkuId(), s.getCount());
            skuMapper.updateStockBySkuId(s.getSkuId(),s.getCount());
        });
        Map<BigInteger, List<SkuStockLockReqDTO>> list = skuStockLocksParam.stream().collect(Collectors.groupingBy(SkuStockLockReqDTO::getSpuId));
        list.forEach((k,v)->{
            int totalNum =  v.stream().mapToInt(SkuStockLockReqDTO::getCount).sum();
            spuMapper.updateSaleNumById(k,totalNum);
            spuExtensionMapper.reduceStockByOrderNotify(k,totalNum);
        });
    }

    /**
     * 根据订单号进行库存解锁
     *
     * @param orderIds 订单ids
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unlockStock(List<BigInteger> orderIds) {
        CommonResult<List<OrderStatusRespDTO>> ordersStatusResp = orderApi.getOrdersStatus(orderIds);
        if (ordersStatusResp.getCode() != GlobalErrorCodeConstants.SUCCESS.getCode()) {
            throw new ServiceException(ordersStatusResp.getCode(), ordersStatusResp.getMsg());
        }
        List<OrderStatusRespDTO> orderStatusList = ordersStatusResp.getData();
        // // 该订单没有下单成功，或订单已取消，赶紧解锁库存
        List<BigInteger> needUnLockOrderId = orderStatusList.stream()
                .filter(order -> order.getStatus() == null && Objects.equals(order.getStatus(), OrderStatusEnum.CLOSE))
                .map(order -> order.getOrderId())
                .collect(Collectors.toList());

        if (CollectionUtil.isEmpty(needUnLockOrderId)) {
            return;
        }

        List<SkuStockLockDO> allSkuWithStocks = skuStockLockMapper.listByOrderIds(needUnLockOrderId);
        if (CollectionUtil.isEmpty(allSkuWithStocks)) {
            return;
        }

        List<BigInteger> lockIds = allSkuWithStocks.stream().map(SkuStockLockDO::getId).collect(Collectors.toList());
        // 还原商品库存
        spuExtensionMapper.addStockByOrder(allSkuWithStocks);
        // 还原sku库存
        skuStockMapper.addStockByOrder(allSkuWithStocks);
        // 将锁定状态标记为已解锁
        skuStockLockMapper.unLockByIds(lockIds);

    }

    /**
     * 正式锁定库存，标记为使用状态
     *
     * @param orderIds 订单ids
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void markerStockUse(List<BigInteger> orderIds) {
        // 查询待确定状态（status=0）的库存锁定
        List<SkuStockLockDO> skuWithStocks = skuStockLockMapper.listByOrderIds(orderIds);

        //  ==============订单从正常状态变成已支付=============
        if (CollectionUtil.isNotEmpty(skuWithStocks)) {
            // 减少商品实际库存，增加销量
            spuExtensionMapper.reduceActualStockByOrder(skuWithStocks);
            // 减少sku实际库存
            skuStockMapper.reduceActualStockByOrder(skuWithStocks);
        }

        // ================ 由于订单支付回调成功过慢，导致订单由取消变成已支付 ====================

        List<SkuStockLockDO> unLockSkuWithStocks = skuStockLockMapper.listUnLockByOrderIds(orderIds);

        if (CollectionUtil.isNotEmpty(unLockSkuWithStocks)) {
            // 减少商品实际库存，增加销量
            spuExtensionMapper.reduceActualStockByCancelOrder(unLockSkuWithStocks);
            // 减少sku实际库存
            skuStockMapper.reduceActualStockByCancelOrder(unLockSkuWithStocks);
        }
        // 将锁定状态标记为已使用
        skuStockLockMapper.markerStockUse(orderIds);
    }

    @Override
    public List<SkuStockDO> getSkuStockList(List<BigInteger> skuIds) {
        return skuStockMapper.selectList(new LambdaQueryWrapperX<SkuStockDO>()
                .in(SkuStockDO::getSkuId, skuIds));
    }


}
